#include "lm_conf_voice_wrapper.h"

namespace lm {
	void CALLBACK FuncVoiceOnDisconnectVoiceServerCB(
		int result, void* clientdata) {
		ConfVoiceWrapper* wrapper = reinterpret_cast<ConfVoiceWrapper*>(clientdata);
		wrapper->OnDisconnectVoiceServerCB(result);
	}

	void CALLBACK FuncVoiceOnDeviceChangeCB(void* clientdata) {
		ConfVoiceWrapper* wrapper = reinterpret_cast<ConfVoiceWrapper*>(clientdata);
		wrapper->OnDeviceChangeCB();
	}

	void ConfVoiceWrapper::OnDisconnectVoiceServerCB(int result) {
		for (ObserverList::iterator it = observer_list_.begin(); it != observer_list_.end(); it++) {
			(*it)->OnDisconnectVoiceServer(result);
		}
	}

	void ConfVoiceWrapper::OnDeviceChangeCB() {
		for (ObserverList::iterator it = observer_list_.begin(); it != observer_list_.end(); it++) {
			(*it)->OnDeviceChange();
		}
	}

	ConfVoiceWrapper::ConfVoiceWrapper(native_object_t c_object)
		: c_object_(c_object) {
		ConfVoiceCallback cb;
		memset(&cb, 0, sizeof(cb));
		cb.client_data_ = this;
		cb.OnDeviceChange_ = FuncVoiceOnDeviceChangeCB;
		cb.OnDisconnectVoiceServer_ = FuncVoiceOnDisconnectVoiceServerCB;
		lm_conf_voice_set_callback(c_object_, &cb);
	}

	ConfVoiceWrapper::~ConfVoiceWrapper() {
	}

	void ConfVoiceWrapper::AddObserver(Observer* observer) {
		if (std::find(observer_list_.begin(), observer_list_.end(), observer) == observer_list_.end())
			observer_list_.push_back(observer);
	}

	void ConfVoiceWrapper::RemoveObserver(Observer* observer) {
		ObserverList::iterator it = std::find(observer_list_.begin(), observer_list_.end(), observer);
		if (it != observer_list_.end())
			observer_list_.erase(it);
	}

	int ConfVoiceWrapper::SetCodecType(LMVoiceCodecModes codec_type, LMVoiceDelayModes delay_mode/* = k120MSDelay*/) {
		return lm_conf_voice_SetCodecType(c_object_, codec_type, delay_mode);
	}

	int ConfVoiceWrapper::GetCodecType(LMVoiceCodecModes& codec_type, LMVoiceDelayModes& delay_mode) {
		return lm_conf_voice_GetCodecType(c_object_,
			reinterpret_cast<int*>(&codec_type), reinterpret_cast<int*>(&delay_mode));
	}

	int ConfVoiceWrapper::SetCodecTypeWithInputDevice(LMVoiceDeviceType input_type,
		LMVoiceCodecModes codec_type, LMVoiceDelayModes delay_mode, int rate) {
		return lm_conf_voice_SetCodecTypeWithInputDevice(c_object_, input_type,codec_type, delay_mode, rate);
	}

	int ConfVoiceWrapper::GetCodecTypeWithInputDevice(LMVoiceDeviceType input_type,
		LMVoiceCodecModes& codec_type, LMVoiceDelayModes& delay_mode, int& rate) {
		return lm_conf_voice_GetCodecTypeWithInputDevice(c_object_, input_type,
			reinterpret_cast<int*>(&codec_type), reinterpret_cast<int*>(&delay_mode), &rate);
	}

	bool ConfVoiceWrapper::IsValidDelayMode(LMVoiceCodecModes codec_type, LMVoiceDelayModes delay_mode) {
		return !!lm_conf_voice_IsValidDelayMode(c_object_, codec_type, delay_mode);
	}

	int ConfVoiceWrapper::GetNumOfInputDevices(int& nums) {
		return lm_conf_voice_GetNumOfInputDevices(c_object_, &nums);
	}

	int ConfVoiceWrapper::GetNumOfOutputDevices(int& nums) {
		return lm_conf_voice_GetNumOfOutputDevices(c_object_, &nums);
	}

	int ConfVoiceWrapper::GetInputDeviceName(int index, char* name, int name_size, char* guid, int guid_size) {
		return lm_conf_voice_GetInputDeviceName(c_object_, index, name, name_size, guid, guid_size);
	}

	int ConfVoiceWrapper::GetOutputDeviceName(int index, char* name, int name_size, char* guid, int guid_size) {
		return lm_conf_voice_GetOutputDeviceName(c_object_, index, name, name_size, guid, guid_size);
	}

	int ConfVoiceWrapper::GetDefaultInputDeviceIndex(int& index) {
		return lm_conf_voice_GetDefaultInputDeviceIndex(c_object_, &index);
	}

	int ConfVoiceWrapper::GetDefaultOutputDeviceIndex(int& index) {
		return lm_conf_voice_GetDefaultOutputDeviceIndex(c_object_, &index);
	}

	int ConfVoiceWrapper::GetCurrentInputDeviceIndex(int& index) {
		return lm_conf_voice_GetCurrentInputDeviceIndex(c_object_, &index);
	}

	int ConfVoiceWrapper::GetCurrentOutputDeviceIndex(int& index) {
		return lm_conf_voice_GetCurrentOutputDeviceIndex(c_object_, &index);
	}

	int ConfVoiceWrapper::GetDefaultInputDeviceName(char* name, int name_size, char* guid, int guid_size) {
		return lm_conf_voice_GetDefaultInputDeviceName(c_object_, name, name_size, guid, guid_size);
	}

	int ConfVoiceWrapper::GetDefaultOutputDeviceName(char* name, int name_size, char* guid, int guid_size) {
		return lm_conf_voice_GetDefaultOutputDeviceName(c_object_, name, name_size, guid, guid_size);
	}

	int ConfVoiceWrapper::GetCurrentInputDeviceName(char* name, int name_size, char* guid, int guid_size) {
		return lm_conf_voice_GetCurrentInputDeviceName(c_object_, name, name_size, guid, guid_size);
	}

	int ConfVoiceWrapper::GetCurrentOutputDeviceName(char* name, int name_size, char* guid, int guid_size) {
		return lm_conf_voice_GetCurrentOutputDeviceName(c_object_, name, name_size, guid, guid_size);
	}

	int ConfVoiceWrapper::SetInputDevice(int index) {
		return lm_conf_voice_SetInputDevice(c_object_, index);
	}

	int ConfVoiceWrapper::SetOutputDevice(int index) {
		return lm_conf_voice_SetOutputDevice(c_object_, index);
	}

	int ConfVoiceWrapper::SetInputVolume(unsigned int volume) {
		return lm_conf_voice_SetInputVolume(c_object_, volume);
	}

	int ConfVoiceWrapper::GetInputVolume(unsigned int& volume) {
		return lm_conf_voice_GetInputVolume(c_object_, &volume);
	}

	int ConfVoiceWrapper::SetOutputVolume(unsigned int volume) {
		return lm_conf_voice_SetOutputVolume(c_object_, volume);
	}

	int ConfVoiceWrapper::GetOutputVolume(unsigned int& volume) {
		return lm_conf_voice_GetOutputVolume(c_object_, &volume);
	}

	int ConfVoiceWrapper::GetInputVoiceLevel(unsigned int& level) {
		return lm_conf_voice_GetInputVoiceLevel(c_object_, &level);
	}

	int ConfVoiceWrapper::GetOutputVoiceLevel(const char* account, unsigned int& level) {
		return lm_conf_voice_GetOutputVoiceLevel(c_object_, account, &level);
	}

	int ConfVoiceWrapper::GetOutputVoiceLevel(int node, unsigned int& level) {
		return lm_conf_voice_GetOutputVoiceLevelWithNode(c_object_, node, &level);
	}

	int ConfVoiceWrapper::SetLoudspeakerStatus(bool enabled) {
		return lm_conf_voice_SetLoudspeakerStatus(c_object_, enabled ? 1 : 0);
	}

	int ConfVoiceWrapper::SetEcStatus(bool enabled, LMEcModes mode/* = kEcUnchanged*/) {
		return lm_conf_voice_SetEcStatus(c_object_, enabled ? 1 : 0, mode);
	}

	int ConfVoiceWrapper::SetNsStatus(bool enabled, LMNsModes mode/* = kNsUnchanged*/) {
		return lm_conf_voice_SetNsStatus(c_object_, enabled ? 1 : 0, mode);
	}

	int ConfVoiceWrapper::SetAgcStatus(bool enabled, LMAgcModes mode/* = kAgcUnchanged*/) {
		return lm_conf_voice_SetAgcStatus(c_object_, enabled ? 1 : 0, mode);
	}

	int ConfVoiceWrapper::SetAecmMode(LMAecmModes mode/* = kAecmSpeakerphone*/, bool enableCNG/* = true*/) {
		return lm_conf_voice_SetAecmMode(c_object_, mode, enableCNG ? 1 : 0);
	}

	int ConfVoiceWrapper::SetVADStatus(bool enable, LMVadModes mode/* = kVadConventional*/, bool disableDTX /*= false*/) {
		return lm_conf_voice_SetVADStatus(c_object_, enable ? 1 : 0, mode, disableDTX ? 1 : 0);
	}

	int ConfVoiceWrapper::GetLoudspeakerStatus(bool& enabled) {
		int v = 0;
		int ret = lm_conf_voice_GetLoudspeakerStatus(c_object_, &v);
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetEcStatus(bool& enabled, LMEcModes& mode) {
		int v = 0;
		int ret = lm_conf_voice_GetEcStatus(c_object_, &v, reinterpret_cast<int*>(&mode));
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetNsStatus(bool& enabled, LMNsModes& mode) {
		int v = 0;
		int ret = lm_conf_voice_GetNsStatus(c_object_, &v, reinterpret_cast<int*>(&mode));
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetAgcStatus(bool& enabled, LMAgcModes& mode) {
		int v = 0;
		int ret = lm_conf_voice_GetAgcStatus(c_object_, &v, reinterpret_cast<int*>(&mode));
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetAecmMode(LMAecmModes& mode, bool& enabledCNG) {
		int v = 0;
		int ret = lm_conf_voice_GetAecmMode(c_object_, reinterpret_cast<int*>(&mode), &v);
		enabledCNG = !!v;
		return ret;
	}
    
	int ConfVoiceWrapper::GetVADStatus(bool& enabled, LMVadModes& mode, bool& disabledDTX) {
		int v = 0;
		int v1 = 0;
		int ret = lm_conf_voice_GetVADStatus(c_object_, &v, reinterpret_cast<int*>(&mode), &v1);
		enabled = !!v;
		disabledDTX = !!v1;
		return ret;
	}

	int ConfVoiceWrapper::EnableDriftCompensation(bool enabled) {
		return lm_conf_voice_EnableDriftCompensation(c_object_, enabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DriftCompensationEnabled(bool &enabled) {
		int v = 0;
		int ret = lm_conf_voice_DriftCompensationEnabled(c_object_, &v);
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::SetDelayOffsetMs(int offset) {
		return lm_conf_voice_SetDelayOffsetMs(c_object_, offset);
	}

	int ConfVoiceWrapper::DelayOffsetMs(int &offset) {
		return lm_conf_voice_DelayOffsetMs(c_object_, &offset);
	}

	int ConfVoiceWrapper::EnableHighPassFilter(bool enabled) {
		return lm_conf_voice_EnableHighPassFilter(c_object_, enabled ? 1 : 0);
	}

	int ConfVoiceWrapper::IsHighPassFilterEnabled(bool &enabled) {
		int v = 0;
		int ret = lm_conf_voice_IsHighPassFilterEnabled(c_object_, &v);
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::EnableInput(bool enabled) {
		return lm_conf_voice_EnableInput(c_object_, enabled ? 1 : 0);
	}

	int ConfVoiceWrapper::EnableOutput(bool enabled) {
		return lm_conf_voice_EnableOutput(c_object_, enabled ? 1 : 0);
	}

	int ConfVoiceWrapper::GetInputState(bool& enabled) {
		int v = 0;
		int ret = lm_conf_voice_GetInputState(c_object_, &v);
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetOutputState(bool& enabled) {
		int v = 0;
		int ret = lm_conf_voice_GetOutputState(c_object_, &v);
		enabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::DisablePlaybackInput(bool disabled) {
		return lm_conf_voice_DisablePlaybackInput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisableIPCameraInput(bool disabled) {
		return lm_conf_voice_DisableIPCameraInput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisableMediaPlayerInput(bool disabled) {
		return lm_conf_voice_DisableMediaPlayerInput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisableExternalDeviceInput(bool disabled) {
		return lm_conf_voice_DisableExternalDeviceInput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisablePlaybackInputLocalOutput(bool disabled) {
		return lm_conf_voice_DisablePlaybackInputLocalOutput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisableIPCameraInputLocalOutput(bool disabled) {
		return lm_conf_voice_DisableIPCameraInputLocalOutput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisableMediaPlayerInputLocalOutput(bool disabled) {
		return lm_conf_voice_DisableMediaPlayerInputLocalOutput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::DisableExternalDeviceInputLocalOutput(bool disabled) {
		return lm_conf_voice_DisableExternalDeviceInputLocalOutput(c_object_, disabled ? 1 : 0);
	}

	int ConfVoiceWrapper::GetDisablePlaybackInputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisablePlaybackInputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisableIPCameraInputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisableIPCameraInputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisableMediaPlayerInputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisableMediaPlayerInputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisableExternalDeviceInputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisableExternalDeviceInputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisablePlaybackInputLocalOutputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisablePlaybackInputLocalOutputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisableIPCameraInputLocalOutputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisableIPCameraInputLocalOutputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisableMediaPlayerInputLocalOutputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisableMediaPlayerInputLocalOutputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::GetDisableExternalDeviceInputLocalOutputState(bool& disabled) {
		int v = 0;
		int ret = lm_conf_voice_GetDisableExternalDeviceInputLocalOutputState(c_object_, &v);
		disabled = !!v;
		return ret;
	}

	int ConfVoiceWrapper::StartPlayingFileLocally(
		int& node,
		const char* fileName,
		bool loop/* = false*/,
		LMVoiceFileFormats format/* = kFileFormatPcm16kHzFile*/,
		float volumeScaling/* = 1.0*/,
		int startPointMs/* = 0*/,
		int stopPointMs/* = 0*/) {
		return lm_conf_voice_StartPlayingFileLocallyFromFile(c_object_, fileName,
			loop ? 1 : 0, format, volumeScaling, startPointMs, stopPointMs, &node);
	}

	int ConfVoiceWrapper::StartPlayingFileLocally(
		int& node,
		const void* stream, int stream_len,
		LMVoiceFileFormats format/* = kFileFormatPcm16kHzFile*/,
		float volumeScaling/* = 1.0*/,
		int startPointMs/* = 0*/, int stopPointMs/* = 0*/) {
		return lm_conf_voice_StartPlayingFileLocallyFromStream(c_object_, stream,
			stream_len, format, volumeScaling, startPointMs, stopPointMs, &node);
	}

	int ConfVoiceWrapper::StopPlayingFileLocally(int node) {
		return lm_conf_voice_StopPlayingFileLocallyWithNode(c_object_, node);
	}

	int ConfVoiceWrapper::IsPlayingFileLocally(int node) {
		return !!lm_conf_voice_IsPlayingFileLocallyWithNode(c_object_, node);
	}

	// Use file as microphone input
	int ConfVoiceWrapper::StartPlayingFileAsMicrophone(
		const char* fileName,
		bool loop/* = false*/,
		bool mixWithMicrophone/* = false*/,
		LMVoiceFileFormats format/* = kFileFormatPcm16kHzFile*/,
		float volumeScaling/* = 1.0*/) {
		return lm_conf_voice_StartPlayingFileAsMicrophoneFromFile(c_object_,
			fileName, loop ? 1 : 0, mixWithMicrophone, format, volumeScaling);
	}

	int ConfVoiceWrapper::StartPlayingFileAsMicrophone(
		const void* stream, int stream_len,
		bool mixWithMicrophone/* = false*/,
		LMVoiceFileFormats format/* = kFileFormatPcm16kHzFile*/,
		float volumeScaling/* = 1.0*/) {
		return lm_conf_voice_StartPlayingFileAsMicrophoneFromStream(c_object_,
			stream, stream_len, mixWithMicrophone, format, volumeScaling);
	}

	int ConfVoiceWrapper::StopPlayingFileAsMicrophone() {
		return lm_conf_voice_StopPlayingFileAsMicrophone(c_object_);
	}

	int ConfVoiceWrapper::IsPlayingFileAsMicrophone() {
		return !!lm_conf_voice_IsPlayingFileAsMicrophone(c_object_);
	}

	int ConfVoiceWrapper::StartRecordingPlayout(
		const char* account,
		const char* fileName,
		LMVoiceCodecModes codec/* = kUnknowVoiceCodec*/ /*or ilbc*/,
		int maxSizeBytes/* = -1*/) {
		return lm_conf_voice_StartRecordingAccountPlayoutToFile(c_object_,
			account, fileName, codec, maxSizeBytes);
	}

	int ConfVoiceWrapper::StartRecordingPlayout(
		const char* account,
		void* stream, int stream_len,
		LMVoiceCodecModes codec/* = kUnknowVoiceCodec*/ /*or ilbc*/) {
		return lm_conf_voice_StartRecordingAccountPlayoutToStream(c_object_,
			account, stream, stream_len, codec);
	}

	int ConfVoiceWrapper::StopRecordingPlayout(const char* account) {
		return lm_conf_voice_StopRecordingAccountPlayout(c_object_,	account);
	}

	int ConfVoiceWrapper::StartRecordingPlayout(
		const char* fileName,
		LMVoiceCodecModes codec /*= kUnknowVoiceCodec*/ /*or ilbc*/,
		int maxSizeBytes/* = -1*/) {
		return lm_conf_voice_StartRecordingAllPlayoutToFile(c_object_,
			fileName, codec, maxSizeBytes);
	}

	int ConfVoiceWrapper::StartRecordingPlayout(
		void* stream, int stream_len,
		LMVoiceCodecModes codec/* = kUnknowVoiceCodec*/ /*or ilbc*/) {
		return lm_conf_voice_StartRecordingAllPlayoutToStream(c_object_,
			stream, stream_len, codec);
	}

	int ConfVoiceWrapper::StopRecordingPlayout() {
		return lm_conf_voice_StopRecordingAllPlayout(c_object_);
	}

	int ConfVoiceWrapper::StartRecordingMicrophone(const char* fileName,
		LMVoiceCodecModes codec/* = kUnknowVoiceCodec*//*or ilbc*/, int maxSizeBytes/* = -1*/) {
		return lm_conf_voice_StartRecordingMicrophoneToFile(c_object_, fileName, codec, maxSizeBytes);
	}

	int ConfVoiceWrapper::StartRecordingMicrophone(void* stream, int stream_len,
		LMVoiceCodecModes codec/* = kUnknowVoiceCodec*//*or ilbc*/) {
		return lm_conf_voice_StartRecordingMicrophoneToStream(c_object_, stream, stream_len, codec);
	}

	int ConfVoiceWrapper::StopRecordingMicrophone() {
		return lm_conf_voice_StopRecordingMicrophone(c_object_);
	}

	int ConfVoiceWrapper::AddIPCamera(const LMIPCameraInfo* info, int camera_channel) {
		return lm_conf_voice_AddIPCamera(c_object_, info, camera_channel);
	}

	int ConfVoiceWrapper::RemoveIPCamera(int identity, int camera_channel) {
		return lm_conf_voice_RemoveIPCamera(c_object_, identity, camera_channel);
	}

	int ConfVoiceWrapper::AddExternalRAWDataInputDevice(int sampleRate, int channel, int identity) {
		return lm_conf_voice_AddExternalRAWDataInputDevice(c_object_, sampleRate, channel, identity);
	}

	int ConfVoiceWrapper::RemoveExternalRAWDataInputDevice(int identity) {
		return lm_conf_voice_RemoveExternalRAWDataInputDevice(c_object_, identity);
	}

	int ConfVoiceWrapper::IncomingExternalInputRAWData(int identity, const void* data, int data_len) {
		return lm_conf_voice_IncomingExternalInputRAWData(c_object_, identity, data, data_len);
	}

	int ConfVoiceWrapper::AddExternalRTPDataInputDevice(int identity) {
		return lm_conf_voice_AddExternalRTPDataInputDevice(c_object_, identity);
	}

	int ConfVoiceWrapper::RemoveExternalRTPDataInputDevice(int identity) {
		return lm_conf_voice_RemoveExternalRTPDataInputDevice(c_object_, identity);
	}

	int ConfVoiceWrapper::IncomingExternalInputRTPData(int identity,
		const void* data, int data_len, LMVoiceDelayModes delay_mode) {
		return lm_conf_voice_IncomingExternalInputRTPData(c_object_, identity, data, data_len, delay_mode);
	}

	int ConfVoiceWrapper::SetVoiceIOMode(LMVoiceIOModes mode) {
		return lm_conf_voice_SetVoiceIOMode(c_object_, mode);
	}

	int ConfVoiceWrapper::GetVoiceIOMode(LMVoiceIOModes& mode) {
		return lm_conf_voice_GetVoiceIOMode(c_object_, reinterpret_cast<int*>(mode));
	}
}